#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

void interpret(char *in, char **out);
void execute(char **tar);
void run(char *tar);
void fullExecute(char **tar, int start, int end);
void fullExecuteHelper(char **tar);
void redirect(char **tar, int cur);

void runCommand(char *tar){
    char *argumentArray[255];
    interpret(tar, argumentArray);
    //execute(argumentArray);
    fullExecuteHelper(argumentArray);
}

void interpret(char *in, char **out){
    char *x, *y;
    x = in;
    strcpy(x,strsep(&x, "\n"));
    int i = 0;
    while(y = strsep(&x," ")){
        if(*y){
            out[i] = y;
            //printf("Out[%d] is: %s.\n",i,out[i]);
            i++;
        }
    }
    out[i++] = NULL;
}

void execute(char **tar){//basic execute command
  if(strcmp(tar[0],"cd")== 0) {
    chdir(tar[1]);
    return;
  }
  char temp[255] = "/bin/";
  strncat(temp, tar[0], 250);
  int childPiD, waitStatus;
  childPiD = fork();
  if (childPiD == 0){
    if(!(execv(tar[0], tar) == -1))
      return;
    else if(!(execv(temp,tar) == -1))
      return;
    else {
        puts("Invalid Command.\n");
        return;
    }
    execv(temp, tar);
  }
  else
    wait(&waitStatus);
}

void fullExecuteHelper(char **tar) {
  int end;
  end = 0;
  while(tar[end]) //seek to the end of the array
    end++;
  fullExecute(tar, 0, end);
}

void fullExecute(char **orig, int start, int end) {//full recursive execute command
  //printf("Calling new loop\n");
  int cur, length;
  cur = end - 1;
  if (cur < 0) 
    return;
  while(strcmp(";",orig[cur]) && strcmp(">",orig[cur]) && strcmp("<",orig[cur]) && strcmp("2>",orig[cur]) && strcmp("|",orig[cur]) && !(cur==start)) //finds the next symbol
    cur--;
  char** tar = orig;
  tar[end] = 0; //truncate end
  if(cur == start){ //base case
    if(cur) {
      int i;
      for(i = 0; i < cur; i++)
        tar++;
    }
    //printf("Executing...\n");
    execute(tar);
    //printf("Executed\n");
  }
  else {
    if(!strcmp(";",tar[cur])) {
      fullExecute(tar, 0, cur); //executes the subset left of the symbol
      fullExecute(tar, cur + 1, end); //executes the right subset
      return;
    }
    else {
      redirect(tar,cur);
    }
  }
}

void redirect(char **tar, int cur) {
  int end = cur;
  if(!strcmp("|",tar[cur])) {
    int fd;
    while(strcmp(";",tar[cur]) && cur) //finds the next symbol
      cur--;
    if(cur) {  //removes the located symbol
      //printf("blahh\n");
      fullExecute(tar, 0, cur);
      //printf("close blahh\n");
      cur++;
    }
    //printf("bypass1\n");
    fd = dup(STDIN_FILENO);
    dup2(STDIN_FILENO,STDOUT_FILENO);
    fullExecute(tar, cur, end);
    //printf("bypass2\n");
    end++;
    cur = end;
    //printf("Cur: %d, %s, End: %d, %s\n", cur, tar[cur], end, tar[end]);
    while(tar[end]) {
      end++;
    }
    fullExecute(tar, cur, end);
    dup2(fd, STDOUT_FILENO);
    return;
  }    
  umask(0000);
  int fd, fd2;
  fd = open(tar[cur + 1], O_WRONLY | O_APPEND | O_CREAT, 0644);
  if (fd == -1) {
    printf("fd: %d, errno: %d, error %s\n", fd, errno, strerror(errno));
    return;
  }
  while(strcmp(";",tar[cur]) && cur) //finds the next symbol
    cur--;
  if(cur) {  //removes the located symbol
    fullExecute(tar, 0, cur);
    cur++;
  }
  if(!strcmp(">",tar[end])) {
    fd2 = dup(STDOUT_FILENO);
    dup2(fd, STDOUT_FILENO);
    fullExecute(tar, cur, end);
    dup2(fd2, STDOUT_FILENO);
    return;
  }
  else if(!strcmp("2>",tar[cur])) {
    fd2 = dup(STDERR_FILENO);
    dup2(fd, STDERR_FILENO);
    fullExecute(tar, cur, end);
    dup2(fd2, STDERR_FILENO);
    return;
  }
  else if(!strcmp("<",tar[cur])) {
    fd2 = dup(STDIN_FILENO);
    dup2(fd,STDIN_FILENO);
    fullExecute(tar, cur, end);
    dup2(fd2,STDIN_FILENO);
    return;
  }
}
